{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "49dab42f",
   "metadata": {},
   "source": [
    "# Counter\n",
    "\n",
    "Let's build a simple counter using Burr. When the counter terminates, print the count and the current time."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84328dc0",
   "metadata": {},
   "source": [
    "## Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "initial_id",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-03-27T00:11:36.093767Z",
     "start_time": "2024-03-27T00:11:36.088301Z"
    },
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "import datetime\n",
    "\n",
    "from burr.core import action, State, ApplicationBuilder, expr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "396c5e0c",
   "metadata": {},
   "source": [
    "## Define actions\n",
    "We define the function `increment()` that has a `State` as input and outputs a new `State`. The decorator `@action` specifies it's a Burr action and it will need to read and write from the `counter` attribute in `State`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "64c67b15363653e9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-03-27T00:11:36.548223Z",
     "start_time": "2024-03-27T00:11:36.539358Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "@action(reads=[\"counter\"], writes=[\"counter\"])\n",
    "def increment(state: State) -> State:\n",
    "    \"\"\"Increment the counter by 1\"\"\"\n",
    "    \n",
    "    # get the value from the `state`\n",
    "    current_count = state[\"counter\"]\n",
    "    current_count += 1\n",
    "\n",
    "    print(\"Count: \", current_count)\n",
    "\n",
    "    # use `.update()` to create a new `State`\n",
    "    return state.update(counter=current_count)\n",
    "\n",
    "\n",
    "@action(reads=[\"counter\"], writes=[])\n",
    "def exit_counter(state: State) -> State:\n",
    "    \"\"\"Print the current count and the current time\"\"\"\n",
    "    current_count = state[\"counter\"]\n",
    "\n",
    "    print(f\"Finished counting to {current_count} at {datetime.datetime.now():%H:%M:%S %Y-%m-%d}\")\n",
    "\n",
    "    return state"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "197106df",
   "metadata": {},
   "source": [
    "## Build the `Application`\n",
    "We pass the action to the `ApplicationBuilder` via `.with_actions()`. Then, we specify the valid transitions between actions: `increment -> increment` and `increment -> exit_counter`. The `expr`ession construct specifies to use the transition `increment -> increment` whenever the `counter` value in state is under ten. Then, default to `increment -> exit_counter` to terminate the application. We also use `.with_entrypoint()` to define where to start and `.with_state()` to set the starting state value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "72ca90a1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: %3 Pages: 1 -->\n",
       "<svg width=\"220pt\" height=\"113pt\"\n",
       " viewBox=\"0.00 0.00 220.00 113.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 109)\">\n",
       "<title>%3</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-109 216,-109 216,4 -4,4\"/>\n",
       "<!-- increment -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>increment</title>\n",
       "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M88,-105C88,-105 20,-105 20,-105 14,-105 8,-99 8,-93 8,-93 8,-80 8,-80 8,-74 14,-68 20,-68 20,-68 88,-68 88,-68 94,-68 100,-74 100,-80 100,-80 100,-93 100,-93 100,-99 94,-105 88,-105\"/>\n",
       "<text text-anchor=\"middle\" x=\"54\" y=\"-82.8\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">increment</text>\n",
       "</g>\n",
       "<!-- increment&#45;&gt;increment -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>increment&#45;&gt;increment</title>\n",
       "<path fill=\"none\" stroke=\"black\" stroke-dasharray=\"5,2\" d=\"M100.02,-92.72C110.41,-92.16 118,-90.09 118,-86.5 118,-84.26 115.03,-82.61 110.27,-81.55\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"110.38,-78.04 100.02,-80.28 109.52,-84.98 110.38,-78.04\"/>\n",
       "<text text-anchor=\"middle\" x=\"165\" y=\"-82.8\" font-family=\"Times,serif\" font-size=\"14.00\">counter &lt; 10</text>\n",
       "</g>\n",
       "<!-- exit_counter -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>exit_counter</title>\n",
       "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M96,-37C96,-37 12,-37 12,-37 6,-37 0,-31 0,-25 0,-25 0,-12 0,-12 0,-6 6,0 12,0 12,0 96,0 96,0 102,0 108,-6 108,-12 108,-12 108,-25 108,-25 108,-31 102,-37 96,-37\"/>\n",
       "<text text-anchor=\"middle\" x=\"54\" y=\"-14.8\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">exit_counter</text>\n",
       "</g>\n",
       "<!-- increment&#45;&gt;exit_counter -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>increment&#45;&gt;exit_counter</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M54,-67.81C54,-61.6 54,-54.45 54,-47.6\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"57.5,-47.24 54,-37.24 50.5,-47.24 57.5,-47.24\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x7f2886e3ead0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "app = (\n",
    "    ApplicationBuilder()\n",
    "    .with_actions(increment, exit_counter)\n",
    "    .with_transitions(\n",
    "        (\"increment\", \"increment\", expr(\"counter < 10\")),\n",
    "        (\"increment\", \"exit_counter\"),\n",
    "    )\n",
    "    .with_state(counter=0)\n",
    "    .with_entrypoint(\"increment\")\n",
    "    .build()\n",
    ")\n",
    "app.visualize(include_conditions=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a63802fa10f73ca8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-03-27T00:11:38.483852Z",
     "start_time": "2024-03-27T00:11:38.463109Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Count:  1\n",
      "Count:  2\n",
      "Count:  3\n",
      "Count:  4\n",
      "Count:  5\n",
      "Count:  6\n",
      "Count:  7\n",
      "Count:  8\n",
      "Count:  9\n",
      "Count:  10\n",
      "Finished counting to 10 at 18:44:29 2024-08-26\n"
     ]
    }
   ],
   "source": [
    "action_obj, result, state = app.run(halt_after=[\"exit_counter\"])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
